// Sikkerhed.cpp: implementation of the CSikkerhed class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include "Sikkerhed.h"
#include "importado.h"
#include "database.h"
#include "FileLogging.h"
#include "rc4.h"
#include "ErrorHandling.h"
#include "EBASDLL.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CSikkerhed * CSikkerhed::_singleton = NULL;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSikkerhed::CSikkerhed()
{
	hProv = 0;

	if (!CryptAcquireContext(&hProv,
							 "Container",
							 NULL,
							 PROV_RSA_FULL,
							 0))
	{
		if (GetLastError() == NTE_BAD_KEYSET)
		{
			if (!CryptAcquireContext(&hProv,
									 "Container",
									 NULL,
									 PROV_RSA_FULL,
									 CRYPT_NEWKEYSET))
			{
				CFileLogging::WriteToFile("CryptAcquireContext FAILED", TRUE);
				hProv = 0;
				return;
			}
		}
	}
}

CSikkerhed::~CSikkerhed()
{
	if (0 != hProv)
		if(!CryptReleaseContext(hProv, 0)) 
			CFileLogging::WriteToFile("CryptReleaseContext FAILED", TRUE);
}

int CSikkerhed::ValidName(const char* text, std::string* msg)
{
/*
	regex expression("([0-9]|[a-z]|[A-Z])+");

	cmatch what;
	if(regex_match(text, what, expression))
	{
		if(msg) 
			msg->assign(what[0]);
		
		return 0;
	}

	if(msg)
		msg->erase();

	return -1;
*/
  msg->assign(text);
  return 0;
}

bool CSikkerhed::IsPasswordComplex(const char* text, std::string* msg)
{
/*
  regex expression("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{7,35}$");

	cmatch what;
	if(regex_match(text, what, expression))
	{
		if(msg) 
			msg->assign(what[0]);
		
		return TRUE;
	}

	if(msg)
		msg->erase();

	return FALSE;
*/
  msg->assign(text);
  return true;
}

bstr_t CSikkerhed::VerificerBruger(bstr_t bruger, bstr_t kode, long adminOption)
{
	BYTE *hash = NULL, *storedHash = NULL;
	long hashLen = 0;
	bstr_t hashStr;
	_variant_t varHash;

	long lower = 0, upper = 0, dif = 0;

	std::string msg;
	ValidName(bruger, &msg);
	if ("" == msg)
		return bstr_t("").copy();

	if (!IsPasswordComplex(kode, &msg))
		return bstr_t("").copy();

	_CommandPtr cmd;
	_RecordsetPtr recordset;

	const char sql[255] = "EBAS_SP_SIKKERHED_SIGNON_BRUGER";
	
	bstr_t blobSql = "SELECT ADGANGSKODE_HASH FROM EBAS_SIKKERHED_BRUGER WHERE BRUGERNAVN = '"+ bruger +"'";

	try {	
/*	
    CDatabase::RetrieveBinary(blobSql, "ADGANGSKODE_HASH", &varHash);
		if (varHash.vt == (VT_ARRAY | VT_UI1)) {
			SafeArrayGetLBound(varHash.parray, 1, &lower);
			SafeArrayGetUBound(varHash.parray, 1, &upper);
			dif = upper - lower;

			storedHash = (BYTE*)malloc(dif + 1);
			memset(storedHash, 0, dif + 1);

			LPVOID lpvoid;
			SafeArrayAccessData(varHash.parray, &lpvoid);
			memcpy(storedHash, lpvoid, dif);
			SafeArrayUnaccessData(varHash.parray);
		}
		make_hash(kode, &hash, &hashLen);
		if (NULL != storedHash) {
			if (memcmp(hash, storedHash, dif))
				return "";
		} else {
			LPVOID lpvoid;
			SAFEARRAYBOUND bound;
			bound.lLbound = 0;
			bound.cElements = hashLen;
			varHash.vt = VT_ARRAY | VT_UI1;
			varHash.parray = SafeArrayCreate(VT_UI1, 1, &bound);
			SafeArrayAccessData(varHash.parray, &lpvoid);
			memcpy(lpvoid, hash, hashLen);
			SafeArrayUnaccessData(varHash.parray);
			CDatabase::StoreBinary(blobSql, "ADGANGSKODE_HASH", &varHash);
		}
*/
		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;

		cmd->Parameters->Append( cmd->CreateParameter("brugernavn", adVarChar, adParamInput, 255, bruger) );
		cmd->Parameters->Append( cmd->CreateParameter("adgangskode", adVarChar, adParamInput, 255, hashStr) );
		cmd->Parameters->Append( cmd->CreateParameter("adminOption", adInteger, adParamInput, sizeof(int), adminOption) );
		cmd->Parameters->Append( cmd->CreateParameter("session", adVarChar, adParamOutput, 255) );

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		

		bstr_t uGuid = recordset->Fields->GetItem("GUID")->Value;
		bstr_t session = recordset->Fields->GetItem("SESSION")->Value;

		if (recordset)
			recordset->Close();

		return session;
	} catch (_com_error &e) {
		long l = (long)e.Error();
		char temp[16];
		ltoa(l, temp, 10);

		CFileLogging::WriteToFile(temp);
		CFileLogging::WriteToFile(e.ErrorMessage());
		CFileLogging::WriteToFile(e.Description());

		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
		return bstr_t("");
	}
}

bool CSikkerhed::SkiftKode(bstr_t bruger, bstr_t gammel, bstr_t ny)
{
	BYTE *hash = NULL, *storedHash = NULL;
	long hashLen = 0;
	bstr_t hashStr;
	_variant_t varHash;

	long lower = 0, upper = 0, dif = 0;

	std::string msg;
	ValidName(bruger, &msg);
	if ("" == msg)
		return FALSE;

	if (!IsPasswordComplex(ny, &msg))
		return FALSE;

	_CommandPtr cmd;
	_RecordsetPtr recordset;

	const char sql[255] = "EBAS_SP_SIKKERHED_SIGNON_BRUGER";
	
	bstr_t blobSql = "SELECT ADGANGSKODE_HASH FROM EBAS_SIKKERHED_BRUGER WHERE BRUGERNAVN = '"+ bruger +"'";

	try {	
		CDatabase::RetrieveBinary(blobSql, "ADGANGSKODE_HASH", &varHash);

		if (varHash.vt == (VT_ARRAY | VT_UI1)) {
			SafeArrayGetLBound(varHash.parray, 1, &lower);
			SafeArrayGetUBound(varHash.parray, 1, &upper);
			dif = upper - lower;

			storedHash = (BYTE*)malloc(dif + 1);
			memset(storedHash, 0, dif + 1);

			LPVOID lpvoid;
			SafeArrayAccessData(varHash.parray, &lpvoid);
			memcpy(storedHash, lpvoid, dif);
			SafeArrayUnaccessData(varHash.parray);
		}
		
		if (NULL != storedHash) {
			make_hash(gammel, &hash, &hashLen);		
			if (memcmp(hash, storedHash, dif))
				return FALSE;
		} 

		if (hash) 
			free(hash);

		make_hash(ny, &hash, &hashLen);

		LPVOID lpvoid;
		SAFEARRAYBOUND bound;
		bound.lLbound = 0;
		bound.cElements = hashLen;

		varHash.vt = VT_ARRAY | VT_UI1;
		varHash.parray = SafeArrayCreate(VT_UI1, 1, &bound);
		SafeArrayAccessData(varHash.parray, &lpvoid);
		memcpy(lpvoid, hash, hashLen);
		SafeArrayUnaccessData(varHash.parray);

		CDatabase::StoreBinary(blobSql, "ADGANGSKODE_HASH", &varHash);
	} catch (_com_error &e) {
		long l = (long)e.Error();
		char temp[16];
		ltoa(l, temp, 10);

		CFileLogging::WriteToFile(temp);
		CFileLogging::WriteToFile(e.ErrorMessage());
		CFileLogging::WriteToFile(e.Description());

		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
		return FALSE;
	} 

	return TRUE;
}

bool CSikkerhed::HentLicensInfo(bstr_t * til, bstr_t * nummer, bstr_t * type, bstr_t * slut)
{
	_CommandPtr cmd;
	_RecordsetPtr recordset;

	const char sql[255] = "EBAS_SP_HENT_LICENS_INFO";

	try {	
		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		

		if (recordset->ADO_EOF)
			return TRUE;

		*til = recordset->Fields->GetItem("LICENS_TIL")->Value;
		*nummer = recordset->Fields->GetItem("LICENS_NUMMER")->Value;
		*type = recordset->Fields->GetItem("LICENS_TYPE")->Value;
		*slut = recordset->Fields->GetItem("SLUT_DATO")->Value;
	} catch (_com_error &e) {
		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
		return FALSE;
	}

	return TRUE;
}

bool CSikkerhed::NulstilAdgangskode(bstr_t brugernavn)
{
	_CommandPtr cmd;
	_RecordsetPtr recordset;

	const char sql[255] = "EBAS_SP_SIKKERHED_NULSTIL_ADGANGSKODE";

	try {	
		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;
		cmd->Parameters->Append( cmd->CreateParameter("brugernavn", adVarChar, adParamInput, 255, brugernavn) );
		cmd->Parameters->Append( cmd->CreateParameter("session", adVarChar, adParamOutput, 255) );

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		

		if (recordset->ADO_EOF)
			return TRUE;
	} catch (_com_error &e) {
		long l = (long)e.Error();
		char temp[16];
		ltoa(l, temp, 10);

		CFileLogging::WriteToFile(temp);
		CFileLogging::WriteToFile(e.ErrorMessage());
		CFileLogging::WriteToFile(e.Description());

		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
		return FALSE;
	}

	return TRUE;
}

bstr_t CSikkerhed::MakeNewPassword(bstr_t bruger)
{
	DWORD d;
	CString csNum;

	GenerateRandom(&d, sizeof d);
	csNum.Format ("%d", d % 1000);	

	return bstr_t(csNum).copy();
}

bool CSikkerhed::GemLicensInfo(bstr_t til, bstr_t nummer, bstr_t slut, long type)
{
	_CommandPtr cmd;
	_RecordsetPtr recordset;

	const char sql[255] = "EBAS_SP_GEM_LICENS_INFO";

	try {
		bstr_t sType;
		BYTE * data = NULL;
		long len = 0;

		if (0 == type)
			sType = EBAS_STANDARD;
		else if (1 == type)
			sType = EBAS_INTERNET;
		else if (2 == type)
			sType = EBAS_EKSAMEN;
		else if (3 == type)
			sType = EBAS_FAKTURA;
		else
			sType = EBAS_TRIAL;

		bstr_t info = til + sType + slut;

		make_licens_key(info, &data, &len);		
		
		char temp[255];
		memset(temp, 0, 255);
		strncpy(temp, (char*)data, len);
		free(data);

		if (bstr_t(nummer) != bstr_t(temp)) {
			CErrorHandling::SetErrorMessage("Ugyldig licens");
			return FALSE;
		}

		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;
    cmd->NamedParameters = true;

    cmd->Parameters->Refresh();
		cmd->Parameters->Append( cmd->CreateParameter("licensTil", adVarChar, adParamInput, 255, til) );
		cmd->Parameters->Append( cmd->CreateParameter("licensNr", adVarChar, adParamInput, 255, bstr_t(temp)) );
		cmd->Parameters->Append( cmd->CreateParameter("licensType", adVarChar, adParamInput, 255, sType) );
		cmd->Parameters->Append( cmd->CreateParameter("slutDato", adVarChar, adParamInput, 255, slut) );

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		
    if (recordset->ADO_EOF) {
			return FALSE;
    }

		bstr_t guid = (bstr_t)recordset->Fields->GetItem("GUID")->Value;

		recordset->Close();

	} catch (_com_error &e) {
		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
    CErrorHandling::SetErrorMessage("Kunne ikke gemme licens info");
		return FALSE;
	}

	return TRUE;
}

bstr_t CSikkerhed::Kryptering(const char * clearText)
{
	const char * pass = "akeDDek65kof4ek2v!khgs";
	
	rc4_key key;
	prepare_key((unsigned char *)pass, strlen(pass), &key);
	
	unsigned char * block = (unsigned char*)malloc(strlen(clearText) +1);
	memset(block, 0, strlen(clearText) +1);
	memcpy(block, clearText, strlen(clearText));
	
	rc4(block, strlen(clearText), &key);

	return bstr_t(block).copy();
}

bool CSikkerhed::VerificerLicens(bstr_t type)
{
	_CommandPtr cmd;
	_RecordsetPtr recordset;

	bstr_t licensTil, licensType, licensSlut, licensNr;

	const char sql[255] = "EBAS_SP_HENT_GYLDIG_LICENSER";

	try {
		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;
    cmd->NamedParameters = true;

		cmd->Parameters->Append( cmd->CreateParameter("type", adVarChar, adParamInput, 255, type) );

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		
		if (recordset->ADO_EOF)
			return FALSE;

		licensTil = (bstr_t)recordset->Fields->GetItem("LICENS_TIL")->Value;
		licensType = (bstr_t)recordset->Fields->GetItem("LICENS_TYPE")->Value;
		licensSlut = (bstr_t)recordset->Fields->GetItem("SLUT_DATO")->Value;
		licensNr = (bstr_t)recordset->Fields->GetItem("LICENS_NUMMER")->Value;

		recordset->Close();

		CString dato = (char*)licensSlut;
		CString year, month, day;

		year = "";
		year += dato.GetAt(6); 
		year += dato.GetAt(7);
		year += dato.GetAt(8);
		year += dato.GetAt(9);
		month = "";
		month += dato.GetAt(3); 
		month += dato.GetAt(4);
		day = "";
		day += dato.GetAt(0); 
		day += dato.GetAt(1);

		dato = year + "-" + month + "-" + day;

		bstr_t info = licensTil + type + dato;

		bstr_t sType;
		BYTE * data = NULL;
		long len = 0;

		make_licens_key(info, &data, &len);		

		char temp[255];
		memset(temp, 0, 255);
		strncpy(temp, (char*)data, len);
		free(data);

		if (bstr_t(licensNr) != bstr_t(temp)) {
			CFileLogging::WriteToFile(licensNr +" == "+ temp);
			CErrorHandling::SetErrorMessage("Ugyldig licens");
			return FALSE;
		}
	} catch (_com_error &e) {
		char err[512];
		strncpy(err, e.ErrorMessage(), 512);

		long l = (long)e.Error();
		char temp[16];
		ltoa(l, temp, 10);

		CFileLogging::WriteToFile(temp);
		CFileLogging::WriteToFile(e.ErrorMessage());
		CFileLogging::WriteToFile(e.Description());

		return FALSE;
	}

	return TRUE;	
}

bool CSikkerhed::MakeTrialLicens(bstr_t navn)
{
	return FALSE;
}

bool CSikkerhed::HentAlleLicenser(_variant_t * licenser)
{
	_CommandPtr cmd;
	_RecordsetPtr recordset;

	bstr_t til, nummer, type, slut;

	const char sql[255] = "EBAS_SP_HENT_LICENS_INFO";

	try {	
		cmd.CreateInstance(__uuidof(Command));
		cmd->ActiveConnection = CDatabase::GetConnection();
		cmd->CommandText = sql;
		cmd->CommandType = adCmdStoredProc;

		recordset = cmd->Execute(NULL, NULL, adCmdStoredProc);		

		if (recordset->ADO_EOF)
			return TRUE;

		SAFEARRAYBOUND bound;
		bound.lLbound = 0;
		bound.cElements = 0;		

		(*licenser).vt = VT_ARRAY | VT_BSTR;
		(*licenser).parray = SafeArrayCreate(VT_BSTR, 2, &bound);

		til = recordset->Fields->GetItem("LICENS_TIL")->Value;
		nummer = recordset->Fields->GetItem("LICENS_NUMMER")->Value;
		type = recordset->Fields->GetItem("LICENS_TYPE")->Value;
		slut = recordset->Fields->GetItem("SLUT_DATO")->Value;

	} catch (_com_error &e) {
		char err[512];
		strncpy(err, e.ErrorMessage(), 512);
		return FALSE;
	}

	return TRUE;
}
